#include "container.hpp"

using namespace Shiny;
using namespace Shiny::Widgets;

WidgetList::WidgetList() : Container()
{
  _typeCode        = type2code<WidgetList>::code;
  _wheelStep       = 10;
  _verticalList    = true;
  _leftToRight     = true;
  _slideEnabled    = true;
  _focusWidget     = 0;
  _focusRect.SetFillColor(sf::Color(0.f, 0.f, 255.f, 100.f));
  _focusSprite.SetColor(sf::Color(255.f, 255.f, 255.f, 100.f));
}

void WidgetList::UpdateListPosition(void)
{
  Children::iterator it  = _children.begin();
  Children::iterator end = _children.end();
  sf::Vector2f       pos;

  pos.x = -_displayedOffset.x;
  pos.y = -_displayedOffset.y;
  for (; it != end ; ++it)
  {
    if (*it == _focusWidget)
    {
      _focusSprite.SetPosition(pos);
      _focusRect.SetPosition(pos);
    }
    (*it)->SetPosition(pos);
    if      (_verticalList)
      pos.y += (*it)->GetHeight();
    else
      pos.x += (*it)->GetWidth();
  }
}

float WidgetList::GetListHeight(void)
{
  Children::iterator it     = _children.begin();
  Children::iterator end    = _children.end();
  float              height = 0;

  for (; it != end ; ++it)
  {
    if      (_verticalList)
      height += (*it)->GetHeight();
    else
      height  = ((*it)->GetWidth() > height) ? (*it)->GetWidth() : height;
  }
  return (height > GetHeight() ? height : GetHeight());
}

float WidgetList::GetListWidth(void)
{
  Children::iterator it    = _children.begin();
  Children::iterator end   = _children.end();
  float              width = 0;

  for (; it != end ; ++it)
  {
    if      (!_verticalList)
      width += (*it)->GetWidth();
    else
      width  = ((*it)->GetWidth() > width) ? (*it)->GetWidth() : width;
  }
  return (width > GetWidth() ? width : GetWidth());
}

void WidgetList::AddWidget(Container* toAdd)
{
  Container::AddWidget(toAdd);
  _listSize = sf::Vector2f(GetListWidth(), GetListHeight());
  UpdateListPosition();
}

void WidgetList::DelWidget(Container* toDel)
{
  Container::DelWidget(toDel);
  _listSize = sf::Vector2f(GetListWidth(), GetListHeight());
  UpdateListPosition();
}

bool WidgetList::EventWheel(const sf::Event event)
{
  if (_slideEnabled)
  {
    if (_verticalList)
      _offsetSlide.y -= event.MouseWheel.Delta * _wheelStep;
    else
      _offsetSlide.x -= event.MouseWheel.Delta * _wheelStep;
    if (_offsetSlide.y < 0)
      _offsetSlide.y = 0;
    else if (_offsetSlide.y + GetHeight() > _listSize.y)
      _offsetSlide.y = _listSize.y - GetHeight();
    if (_offsetSlide.x < 0)
      _offsetSlide.x = 0;
    else if (_offsetSlide.x + GetWidth() > _listSize.x)
      _offsetSlide.x = _listSize.x - GetWidth();
    UpdateListPosition();
  }
  return (Container::EventWheel(event));
}

#define ABS(x) (x > 0 ? x : -x)

void WidgetList::RefreshOffset(void)
{
  float elapsedTime = _refreshClock.GetElapsedTime().AsMilliseconds();
  
  if (_offsetSlide.x != _displayedOffset.x)
  {
    if (_offsetSlide.x > _displayedOffset.x)
    {
      _displayedOffset.x += 0.5 * elapsedTime;
      if ((ABS(_offsetSlide.x - _displayedOffset.x)) <= 0.5f)
	_offsetSlide.x = _displayedOffset.x;
    }
    else
    {
      _displayedOffset.x -= 0.5 * elapsedTime;
      if ((ABS(_displayedOffset.x - _offsetSlide.x)) <= 0.5f)
	_offsetSlide.x = _displayedOffset.x;
    }
  }
  if (_offsetSlide.y != _displayedOffset.y)
  {
    if (_offsetSlide.y > _displayedOffset.y)
    {
      _displayedOffset.y += 0.5 * elapsedTime;
      if ((ABS(_offsetSlide.y - _displayedOffset.y)) <= 0.5f)
	_offsetSlide.y = _displayedOffset.y;
    }
    else
    {
      _displayedOffset.y -= 0.5 * elapsedTime;
      if ((ABS(_displayedOffset.y - _offsetSlide.y)) <= 0.5f)
	_offsetSlide.y = _displayedOffset.y;
    }
  }
  UpdateListPosition();
}

void WidgetList::RenderSelf(void)
{
  if (_offsetSlide.x != _displayedOffset.x || _offsetSlide.y != _displayedOffset.y)
    RefreshOffset();
  Container::RenderSelf();
  this->Draw(_focusRect);
}

void WidgetList::PostRender(void)
{
}

void WidgetList::TakeFocus(Container* focus)
{
  if (focus != _focusWidget)
  {
    std::cout << "List take focus: " << focus->GetName() << std::endl;
    _focusWidget  = focus;
    _focusRect.SetPosition(_focusWidget->GetPosition());
    _focusRect.SetSize(sf::Vector2f(focus->GetWidth(), focus->GetHeight()));
    SelectionChanged.Emit(focus);
  }
  SelfFocus();
}
